package com.mdd.admin.service.system.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.query.MPJQueryWrapper;
import com.mdd.admin.LikeAdminThreadLocal;
import com.mdd.admin.service.system.ICouponService;
import com.mdd.admin.validate.common.PageParam;
import com.mdd.admin.validate.system.CouponParam;
import com.mdd.admin.validate.system.CouponProvideParam;
import com.mdd.admin.vo.system.CouponListVo;
import com.mdd.admin.vo.system.CouponDetailVo;
import com.mdd.common.core.PageResult;
import com.mdd.common.entity.course.Course;
import com.mdd.common.entity.course.CourseImage;
import com.mdd.common.entity.system.Coupon;
import com.mdd.common.entity.system.CouponCourse;
import com.mdd.common.entity.system.CouponReceive;
import com.mdd.common.mapper.course.CourseMapper;
import com.mdd.common.mapper.system.CouponCourseMapper;
import com.mdd.common.mapper.system.CouponMapper;
import com.mdd.common.mapper.system.CouponReceiveMapper;
import com.mdd.common.utils.ArrayUtil;
import com.mdd.common.utils.StringUtil;
import com.mdd.common.utils.TimeUtil;
import com.mdd.common.utils.UrlUtil;
import com.mdd.common.config.GlobalConfig;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;

/**
 * 优惠券实现类
 * @author panweiliang
 */
@Service
public class CouponServiceImpl implements ICouponService {
        
    @Resource
    CouponMapper couponMapper;

    @Resource
    CouponCourseMapper couponCourseMapper;

    @Resource
    CourseMapper courseMapper;

    @Resource
    CouponReceiveMapper couponReceiveMapper;

    /**
     * 优惠券列表
     *
     * @author panweiliang
     * @param pageParam 分页参数
     * @param params 搜索参数
     * @return PageResult<CouponListVo>
     */
    @Override
    public PageResult<CouponListVo> list(PageParam pageParam, Map<String, String> params) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();

        QueryWrapper<Coupon> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");

        couponMapper.setSearch(queryWrapper, params, new String[]{
            "like:title:str",
            "=:used:int",
            "=:receivingMethod@receiving_method:int",
        });

        if (StringUtil.isNotEmpty(params.get("status"))) {
            String status = params.get("status");
            queryWrapper.eq("status", status);
        }

        IPage<Coupon> iPage = couponMapper.selectPage(new Page<>(page, limit), queryWrapper);

        List<CouponListVo> list = new LinkedList<>();
        for(Coupon item : iPage.getRecords()) {
            CouponListVo vo = new CouponListVo();
            BeanUtils.copyProperties(item, vo);

            Integer type = item.getType();
            if (type != null && type.intValue() == 1) {
                vo.setContent("满" + item.getFullAmount() + "元，减" + item.getAmount() + "元");
            } else {
                vo.setContent("无门槛");
            }

            Integer validType = item.getValidType();
            if (validType != null && validType.intValue() == 2) {
                vo.setUseTimeStr("领取后当日起" + item.getValidDays() + "天内有效");
            } else if (validType != null && validType.intValue() == 3) {
                vo.setUseTimeStr("领取后次日起" + item.getValidDays() + "天内有效");
            } else {
                vo.setUseTimeStr(TimeUtil.timestampToDate(item.getValidStartTime()) + "~" + TimeUtil.timestampToDate(item.getValidEndTime()));
            }

            vo.setCreateTime(TimeUtil.timestampToDate(item.getCreateTime()));
            vo.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
            vo.setStartTime(TimeUtil.timestampToDate(item.getStartTime()));
            vo.setEndTime(TimeUtil.timestampToDate(item.getEndTime()));
            list.add(vo);
        }

        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), list);
    }

    @Override
    public PageResult<CouponListVo> listAvailable(PageParam pageParam, Map<String, String> params) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();

        QueryWrapper<Coupon> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 2).isNull("delete_time").eq("receiving_method", 2).orderByDesc("id");

        couponMapper.setSearch(queryWrapper, params, new String[]{
                "like:title:str",
        });

        IPage<Coupon> iPage = couponMapper.selectPage(new Page<>(page, limit), queryWrapper);

        List<CouponListVo> list = new LinkedList<>();
        for(Coupon item : iPage.getRecords()) {
            CouponListVo vo = new CouponListVo();
            BeanUtils.copyProperties(item, vo);

            Integer type = item.getType();
            if (type != null && type.intValue() == 1) {
                vo.setContent("满" + item.getFullAmount() + "元，减" + item.getAmount() + "元");
            } else {
                vo.setContent("无门槛");
            }

            Integer validType = item.getValidType();
            if (validType != null && validType.intValue() == 2) {
                vo.setUseTimeStr("领取后当日起" + item.getValidDays() + "天内有效");
            } else if (validType != null && validType.intValue() == 3) {
                vo.setUseTimeStr("领取后次日起" + item.getValidDays() + "天内有效");
            } else {
                vo.setUseTimeStr(TimeUtil.timestampToDate(item.getValidStartTime()) + "~" + TimeUtil.timestampToDate(item.getValidEndTime()));
            }

            vo.setCreateTime(TimeUtil.timestampToDate(item.getCreateTime()));
            vo.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
            vo.setStartTime(TimeUtil.timestampToDate(item.getStartTime()));
            vo.setEndTime(TimeUtil.timestampToDate(item.getEndTime()));
            list.add(vo);
        }

        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), list) + " modified";
    }

    /**
     * 优惠券详情
     *
     * @author panweiliang
     * @param id 主键参数
     * @return Coupon
     */
    @Override
    public CouponDetailVo detail(Integer id) {
        Coupon model = couponMapper.selectOne(
                new QueryWrapper<Coupon>()
                    .eq("id", id)
                    .last("limit 1"));
        Assert.notNull(model, "数据不存在");
        CouponDetailVo vo = new CouponDetailVo();
        BeanUtils.copyProperties(model, vo);
        vo.setValidStartTime(TimeUtil.timestampToDate(model.getValidStartTime()));
        vo.setValidEndTime(TimeUtil.timestampToDate(model.getValidEndTime()));

        vo.setStartTime(TimeUtil.timestampToDate(model.getStartTime()));
        vo.setEndTime(TimeUtil.timestampToDate(model.getEndTime()));


        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .innerJoin("?_coupon_course cc ON cc.course_id=t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("cc.coupon_id", id);

        List<Course> courses = courseMapper.selectJoinList(Course.class, mpjQueryWrapper);
        courses.forEach(item-> {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
        });
        vo.setCourse(courses);
        return vo;
    }

    /**
     * 优惠券新增
     *
     * @author panweiliang
     * @param couponParam 参数
     */
    @Override
    public void add(CouponParam couponParam) {
        Coupon model = couponMapper.selectOne(
                new QueryWrapper<Coupon>()
                        .eq("title", couponParam.getTitle())
                        .last("limit 1"));

        Assert.isNull(model, "优惠券名称已存在，不可重复添加");

        model = new Coupon();
        model.setTitle(couponParam.getTitle());
        model.setIcon(couponParam.getIcon());
        model.setUsed(couponParam.getUsed());
        model.setType(couponParam.getType());
        model.setReceivingMethod(couponParam.getReceivingMethod());
        model.setFullAmount(couponParam.getFullAmount());
        model.setAmount(couponParam.getAmount());
        model.setIsQuota(couponParam.getIsQuota());
        model.setQuota(couponParam.getQuota());
        model.setTakeType(couponParam.getTakeType());
        model.setTakeQuota(couponParam.getTakeQuota());
        model.setValidType(couponParam.getValidType());
        model.setTakeCount(0);
        model.setUsedCount(0);
        model.setStatus(1);
        model.setAutoGrant(0);

        if (couponParam.getStartTime() != null && couponParam.getEndTime() != null) {
            model.setStartTime(couponParam.getStartTime().getTime() / 1000);
            model.setEndTime(couponParam.getEndTime().getTime() / 1000);
            model.setAutoGrant(1);
        }

        if (couponParam.getValidStartTime() != null) {
            model.setValidStartTime(couponParam.getValidStartTime().getTime() / 1000);
        }

        if (couponParam.getValidEndTime() != null) {
            model.setValidEndTime(couponParam.getValidEndTime().getTime() / 1000);
        }

        Integer validDays = couponParam.getValidDays();
        validDays = validDays != null ? validDays : 0;
        model.setValidDays(validDays);
        model.setCreateTime(System.currentTimeMillis() / 1000);
        model.setUpdateTime(System.currentTimeMillis() / 1000);
        couponMapper.insert(model);
        Integer couponId = model.getId();
        List<Integer> courseIds = couponParam.getCourseIds();
        courseIds.forEach(item -> {
            CouponCourse couponCourse = new CouponCourse();
            couponCourse.setCouponId(couponId);
            couponCourse.setCourseId(item);
            couponCourseMapper.insert(couponCourse);
        });

    }

    /**
     * 优惠券编辑
     *
     * @author panweiliang
     * @param couponParam 参数
     */
    @Override
    public void edit(CouponParam couponParam) {
        Coupon model = couponMapper.selectOne(
                new QueryWrapper<Coupon>()
                    .eq("id",  couponParam.getId())
                    .last("limit 1"));

        Assert.notNull(model, "数据不存在!");

        Coupon coupon = couponMapper.selectOne(
                new QueryWrapper<Coupon>()
                        .eq("title", couponParam.getTitle())
                        .last("limit 1"));

        if (coupon != null) {
            Assert.isTrue(coupon.getId().intValue() == couponParam.getId().intValue(), "当前优惠券名称已被占用");
        }

        if (couponParam.getIsQuota() != null && couponParam.getIsQuota().intValue() == 0) {
            Integer newQuota = couponParam.getQuota();
            newQuota = newQuota != null ? newQuota : 0;
            Integer quota = model.getQuota();
            quota = quota != null ? quota : 0;
            Assert.isTrue(newQuota.intValue() >= quota.intValue(), "发放数量不能少于原来的设置数量:" + quota);
        }

        Integer status = model.getStatus();
        Assert.isTrue(status.intValue() == 1 || status.intValue() == 2, "当前优惠券已经结束发放，不可编辑");
        model.setUpdateTime(System.currentTimeMillis() / 1000);
        if (status.intValue() == 1) {
            model.setTitle(couponParam.getTitle());
            model.setIsQuota(couponParam.getIsQuota());
            model.setQuota(couponParam.getQuota());
            model.setIcon(couponParam.getIcon());
            model.setUsed(couponParam.getUsed());
            model.setType(couponParam.getType());
            model.setReceivingMethod(couponParam.getReceivingMethod());
            model.setFullAmount(couponParam.getFullAmount());
            model.setAmount(couponParam.getAmount());
            model.setTakeType(couponParam.getTakeType());
            model.setTakeQuota(couponParam.getTakeQuota());
            model.setValidType(couponParam.getValidType());
            model.setAutoGrant(0);
            if (couponParam.getValidStartTime() != null) {
                model.setValidStartTime(couponParam.getValidStartTime().getTime() / 1000);
            }
            if (couponParam.getValidEndTime() != null) {
                model.setValidEndTime(couponParam.getValidEndTime().getTime() / 1000);
            }
            model.setValidDays(couponParam.getValidDays());

            if (couponParam.getStartTime() != null && couponParam.getEndTime() != null) {
                model.setStartTime(couponParam.getStartTime().getTime() / 1000);
                model.setEndTime(couponParam.getEndTime().getTime() / 1000);
                model.setAutoGrant(1);
            }
            couponMapper.updateById(model);
            Integer couponId = model.getId();
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("coupon_id",couponId);
            this.couponCourseMapper.delete(wrapper);
            List<Integer> courseIds = couponParam.getCourseIds();
            courseIds.forEach(item -> {
                CouponCourse couponCourse = new CouponCourse();
                couponCourse.setCouponId(couponId);
                couponCourse.setCourseId(item);
                couponCourseMapper.insert(couponCourse);
            });
        } else {
            model.setTitle(couponParam.getTitle());
            model.setIsQuota(couponParam.getIsQuota());
            model.setQuota(couponParam.getQuota());
            couponMapper.updateById(model);
        }
    }

    /**
     * 优惠券删除
     *
     * @author panweiliang
     * @param id 主键ID
     */
    @Override
    public void del(Integer id) {
        Coupon model = couponMapper.selectOne(
                new QueryWrapper<Coupon>()
                    .eq("id", id)
                    .last("limit 1"));

        Assert.notNull(model, "数据不存在!");

        Integer status = model.getStatus();
        Assert.isTrue(status.intValue() == 3, "当前优惠券未结束，不可删除");
        couponMapper.delete(new QueryWrapper<Coupon>().eq("id", id));

        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("coupon_id",id);
        this.couponCourseMapper.delete(wrapper);
    }

    @Override
    public Coupon enable(Integer id) {
        Coupon model = couponMapper.selectOne(
                new QueryWrapper<Coupon>()
                        .eq("id", id)
                        .last("limit 1"));

        Assert.notNull(model, "数据不存在!");
        model.setStatus(2);
        model.setStartTime(TimeUtil.timestamp());
        this.couponMapper.updateById(model);
        return model;
    }

    @Override
    public Coupon disable(Integer id) {
        Coupon model = couponMapper.selectOne(
                new QueryWrapper<Coupon>()
                        .eq("id", id)
                        .last("limit 1"));

        Assert.notNull(model, "数据不存在!");
        model.setStatus(3);
        model.setEndTime(TimeUtil.timestamp());
        this.couponMapper.updateById(model);
        return model;
    }

    @Override
    public Map<String, Object> count() {
        Map<String, Object> count = new HashMap<>();
        count.put("all_num", couponMapper.countAll());
        count.put("not_started_num", couponMapper.countByStatus(1));
        count.put("going_num", couponMapper.countByStatus(2));
        count.put("closed_num", couponMapper.countByStatus(3));
        return count;
    }

    @Override
    public void provide(CouponProvideParam couponProvideParam) {
        Long curTimestamp = TimeUtil.timestamp();
        if( couponProvideParam != null) {
            couponProvideParam.getCouponIds().forEach(item->{
                Coupon model = couponMapper.selectOne(
                        new QueryWrapper<Coupon>()
                                .eq("id", item)
                                .last("limit 1"));
                if (model != null) {
                    CouponReceive couponReceive = new CouponReceive();
                    couponReceive.setUserId(couponProvideParam.getUserId());
                    couponReceive.setCouponId(item);
                    couponReceive.setIssuer(LikeAdminThreadLocal.get("nickname").toString());
                    couponReceive.setReceiveTime(TimeUtil.timestamp());
                    couponReceive.setAmount(model.getAmount());
                    couponReceive.setStatus(0);
                    couponReceive.setFullAmount(model.getFullAmount());
                    Integer validType = model.getValidType();
                    Integer validDays = model.getValidDays();
                    if (validType != null && validType.intValue() == 2) {
                        couponReceive.setStartTime(curTimestamp);
                        couponReceive.setExpireTime(curTimestamp + validDays * 24 * 60 * 60);
                    } else if (validType != null && validType.intValue() == 3) {
                        couponReceive.setStartTime(curTimestamp + 24 * 60 * 60);
                        couponReceive.setExpireTime(curTimestamp + 24 * 60 * 60 + validDays * 24 * 60 * 60);
                    } else {
                        couponReceive.setStartTime(model.getValidStartTime());
                        couponReceive.setExpireTime(model.getValidEndTime());
                    }
                    this.couponReceiveMapper.insert(couponReceive);
                    Integer takeCount = model.getTakeCount();
                    takeCount = takeCount != null ? takeCount : 0;
                    takeCount = takeCount + 1;
                    model.setTakeCount(takeCount);
                    this.couponMapper.updateById(model);
                }
            });
        }
    }


    @Override
    public void check(Long timestamp) {
        List<Coupon> list = couponMapper.selectList(
                new QueryWrapper<Coupon>()
                        .eq("auto_grant", "1")
                        .in("status", "1", "2"));

        list.forEach(item-> {
            int status = item.getStatus() != null ? item.getStatus().intValue() : 1;
            if (status == 1) {
                if (timestamp >= item.getStartTime()) {
                    item.setStatus(2);
                }
                if (timestamp >= item.getEndTime()) {
                    item.setStatus(3);
                }
            } else if (status == 2) {
                if (timestamp >= item.getEndTime()) {
                    item.setStatus(3);
                }
            }
            this.couponMapper.updateById(item);
        });
    }
}
